package own.stu.jobgib.playown.redis.redisson;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.misc.AsyncSemaphore;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Slf4j
public class AsyncSemaphoreTest {

    @SneakyThrows
    public static void main(String[] args) {
        log.info(" ---- start --------- ");
        CountDownLatch latch = new CountDownLatch(2);
        AsyncSemaphore semaphore = new AsyncSemaphore(1);
        new Thread(() -> doRun(semaphore, latch), "t1").start();
        new Thread(() -> doRun(semaphore, latch), "t2").start();

        latch.await();
        log.info(" ---- end --------- ");
    }

    private static void doRun(AsyncSemaphore semaphore, CountDownLatch latch) {
        semaphore.acquire().thenAccept((v) -> {
            log.info("time[{}] - {} : do ... {}", new Date(), Thread.currentThread().getName(), v);
            try {
                log.info("{} : time : {}", Thread.currentThread().getName(), new Date());
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            semaphore.release();
        });
        log.info(" {} --- continue ... do sth ", Thread.currentThread().getName());
        latch.countDown();
    }

    public static void main_2(String[] args) {

        RedissonClient client = Redisson.create();

        ExecutorService executorService = Executors.newFixedThreadPool(10);
        executorService.submit(() -> {
            try {
                client.getLock("lock1");
            } finally {

            }
        });

        executorService.submit(() -> {
            client.getLock("lock1");
        });

    }

    public static void main_3(String[] args) {
        Solution s = new Solution();
//        System.out.println(s.firstMissingPositive(new int[]{1,2,0}));
//        System.out.println(s.firstMissingPositive(new int[]{3,4,-1,1}));
//        System.out.println(s.firstMissingPositive(new int[]{7,8,9,11,12}));
//        System.out.println(s.firstMissingPositive(new int[]{2,1}));
//        System.out.println(s.firstMissingPositive(new int[]{1,1}));

//        System.out.println(s.firstMissingPositive_ii(new int[]{1,2,0}));
//        System.out.println(s.firstMissingPositive_ii(new int[]{3,4,-1,1}));
//        System.out.println(s.firstMissingPositive_ii(new int[]{7,8,9,11,12}));
//        System.out.println(s.firstMissingPositive_ii(new int[]{2,1}));
//        System.out.println(s.firstMissingPositive_ii(new int[]{1,1}));
//        System.out.println(s.firstMissingPositive_ii(new int[]{1}));

//        s.mySqrt(223456786);

        long x = 7343131546421476L;
/*
        TreeMap<Integer, Integer> map = new TreeMap<>();
        map.put(1, 1);
        map.put(3, 3);
        map.put(5, 5);
        System.out.println(map.floorKey(3));
        System.out.println(map.floorKey(4));

        new ArrayList<>();*/

        //System.out.println(s.generateParenthesis(2));
//        System.out.println(s.generateParenthesis(2));

        /*String str =")()(";
        for(int j = 0; j < str.length();j ++) {
            String newStr = str.substring(0, j) + str.substring(j + 1, str.length());
            System.out.println(newStr);
        }*/

//        System.out.println(s.calculate("3 + 223"));
//        System.out.println(s.calculate("3 + 223 + （-10 * -10"));

//        System.out.println(s.countSmaller(new int[]{5,2,6,1}));

//        int i = 5525511135;
        Solution2 s2 = new Solution2();
        /*s2.flatten(new TreeNode(1,
                new TreeNode(2,
                        new TreeNode(3), new TreeNode(4)),
                new TreeNode(5,
                        null, new TreeNode(6))));*/

        /*s2.flatten(new TreeNode(1, new TreeNode(2), new TreeNode(5)));*/

        Solution3 s3 = new Solution3();
        s3.pacificAtlantic(new int[][]{
                {1, 2, 2, 3, 5},
                {7, 2, 3, 4, 4},
                {2, 4, 2, 3, 1},
                {6, 7, 6, 4, 5},
                {5, 1, 1, 2, 4}
        });
        System.out.println();
    }

    public static class Solution3 {
        /**
         * @param matrix: the given matrix
         * @return: The list of grid coordinates
         * we will sort your return value in output
         */
        public List<List<Integer>> pacificAtlantic(int[][] matrix) {
            // write your code here
            List<List<Integer>> ans = new ArrayList<>();
            if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
                return ans;
            }
            int row = matrix.length, col = matrix[0].length;
            Deque<int[]> points = new LinkedList<>();
            boolean[][] visited = new boolean[row][col];
            for (int i = 0; i < col; i++) {
                points.addFirst(new int[]{0, i});
                visited[0][i] = true;
            }
            for (int i = 1; i < row; i++) {
                points.addFirst(new int[]{i, 0});
                visited[i][0] = true;
            }
            List<String> result1 = bfs(matrix, visited, points);
            if (result1.size() == 0) return ans;

            points.clear();
            visited = new boolean[row][col];
            for (int i = 0; i < col; i++) {
                points.addFirst(new int[]{row - 1, i});
                visited[row - 1][i] = true;
            }
            for (int i = 1; i < row; i++) {
                points.addFirst(new int[]{i, col - 1});
                visited[i][col - 1] = true;
            }
            List<String> result2 = bfs(matrix, visited, points);
            if (result2.size() == 0) return ans;

            Set<String> map = new HashSet<>();
            for (String s : result1) {
                map.add(s);
            }

            for (String s : result2) {

                if (map.contains(s)) {

                    // System.out.println(s);
                    String[] strs = s.split("\\.");
                    ans.add(Arrays.asList(Integer.valueOf(strs[0]), Integer.valueOf(strs[1])));
                }
            }

            return ans;
        }

        private List<String> bfs(int[][] matrix, boolean[][] visited, Deque<int[]> points) {
            List<String> list = new ArrayList<>();
            while (!points.isEmpty()) {
                int size = points.size();
                boolean higher = true;
                for (int i = 0; i < size; i++) {
                    int[] p1 = points.pollFirst();
                    for (int d = 0; d < dx.length; d++) {
                        int x = p1[0] + dx[d];
                        int y = p1[1] + dy[d];
                        if (x < 0 || x >= matrix.length || y < 0 || y >= matrix[0].length) {
                            continue;
                        }
                        if (visited[x][y]) {
                            continue;
                        }
                        visited[x][y] = true;
                        if (matrix[x][y] > matrix[p1[0]][p1[1]]) {
                            higher = false;
                        }
                        points.addLast(new int[]{x, y});
                    }
                    if (higher) {
                        list.add(p1[0] + "." + p1[1]);
                    }
                }
            }
            return list;
        }

        private static int[] dx = {0, 0, 1, -1};
        private static int[] dy = {1, -1, 0, 0};
    }

    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode() {
        }

        TreeNode(int val) {
            this.val = val;
        }

        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }

    static class Solution2 {
        /**
         * Definition for a binary tree node.
         */

        TreeNode pre;

        public void flatten(TreeNode root) {
            if (root == null) {
                return;
            }
            helper(root);
        }

        private void helper(TreeNode node) {
            if (node == null) return;

            helper(node.left);
            helper(node.right);


        }
    }

    static class Solution {

        public List<Integer> countSmaller(int[] nums) {
            List<Integer> ans = new ArrayList<>();
            if (nums == null || nums.length == 0) {
                return ans;
            }
            int n = nums.length;
            Item[] items = new Item[n];
            for (int i = 0; i < n; i++) {
                items[i] = new Item(nums[i], i);
            }
            int[] cnt = new int[n];

            merge(items, 0, n - 1, cnt);

            for (int i : cnt) {
                ans.add(i);
            }
            return ans;
        }

        private void merge(Item[] items, int lo, int hi, int[] cnt) {
            if (lo >= hi) return;
            int mid = lo + ((hi - lo) >> 1);
            merge(items, lo, mid, cnt);
            merge(items, mid + 1, hi, cnt);
            sort(items, lo, mid, mid + 1, hi, cnt);
        }

        private void sort(Item[] items, int lo, int loEnd, int hi, int hiEnd, int[] cnt) {
            System.out.println(lo + " - " + loEnd + ", " + hi + " - " + hiEnd);
            int len = hiEnd - lo + 1;
            Item[] sorted = new Item[len];
            int i = lo, j = hi;
            int rightCnt = 0;

            int idx = 0;
            while (i <= loEnd && j <= hiEnd) {
                System.out.println(i + ", " + j);
                if (items[j].val < items[i].val) {
                    rightCnt++;
                    sorted[idx++] = items[j++];
                } else {
                    cnt[items[i].idx] += rightCnt;
                    sorted[idx++] = items[i++];
                }
            }

            while (i <= loEnd) {
                cnt[items[i].idx] += rightCnt;
                sorted[idx++] = items[i++];
            }

            while (j <= hiEnd) {
                sorted[idx++] = items[j++];
            }

            System.arraycopy(sorted, 0, items, lo, len);
        }

        class Item {
            int val;
            int idx;

            public Item(int val, int idx) {
                this.val = val;
                this.idx = idx;
            }
        }

        public int calculate(String s) {
            if (s == null || s.length() == 0) {
                return 0;
            }
            // 将所有的空格去掉
            s = s.replaceAll(" ", "");

            int n = s.length();
            char[] cs = s.toCharArray();
            Deque<Character> ops = new LinkedList<>();
            Deque<Integer> nums = new LinkedList<>();
            // 为了防止第一个数为负数，先往 nums 加个 0
            nums.addLast(0);
            for (int i = 0; i < n; i++) {
                char c = cs[i];
                if (c == '(') ops.addLast(c);
                else if (c == ')') {
                    while (!ops.isEmpty()) {
                        if (ops.peekLast() != '(') {
                            calc(nums, ops);
                        } else {
                            ops.pollLast();
                            break;
                        }
                    }
                } else {
                    if (isNum(c)) {
                        int j = i;
                        // 将从 i 位置开始后面的连续数字整体取出，加入 nums
                        StringBuilder sb = new StringBuilder();
                        while (j < n && isNum(cs[j])) {
                            sb.append(cs[j]);
                            j++;
                        }
                        i = j - 1;
                        nums.addLast(Integer.valueOf(sb.toString()));
                    } else {
                        if (i > 0 && (cs[i - 1] == '(' || cs[i - 1] == '+' || cs[i - 1] == '-')) {
                            nums.addLast(0);
                        }
                        // 有一个新操作要入栈时，先把栈内可以算的都算了
                        // 只有满足「栈内运算符」比「当前运算符」优先级高/同等，才进行运算
                        while (!ops.isEmpty() && ops.peekLast() != '(') {
                            char prev = ops.peekLast();
                            if (map.get(prev) >= map.get(c)) {
                                calc(nums, ops);
                            } else {
                                break;
                            }
                        }
                        ops.addLast(c);
                    }
                }
            }

            PriorityQueue<Integer> fuel = new PriorityQueue<>((a, b) -> {
                return b - a;
            });

            // 将剩余的计算完
            while (!ops.isEmpty()) calc(nums, ops);
            return nums.peekLast();
        }

        void calc(Deque<Integer> nums, Deque<Character> ops) {
            if (nums.isEmpty() || nums.size() < 2) return;
            if (ops.isEmpty()) return;
            int b = nums.pollLast(), a = nums.pollLast();
            char op = ops.pollLast();
            int ans = ope(a, b, op);
            nums.addLast(ans);
        }

        // 使用 map 维护一个运算符优先级
        // 这里的优先级划分按照「数学」进行划分即可
        private static Map<Character, Integer> map = new HashMap<Character, Integer>() {{
            put('-', 1);
            put('+', 1);
            put('*', 2);
            put('/', 2);
            put('%', 2);
            put('^', 3);
        }};

        private boolean isNum(char c) {
            return c >= '0' && c <= '9';
        }

        private int ope(int n1, int n2, char op) {
            if (op == '+') {
                return n1 + n2;
            } else if (op == '-') {
                return n1 - n2;
            } else if (op == '*') {
                return n1 * n2;
            } else {
                return n1 / n2;
            }
        }

        public int longestValidParentheses(String s) {
            if (s == null || s.length() == 0) {
                return 0;
            }
            int n = s.length();
            char[] cs = s.toCharArray();
            /**
             dp[i] 表示以i为结尾的子串的最长有效括号的长度
             - s[i] = ')' & s[i - 1] = '('
             => dp[i] = dp[i - 2] + 2
             - s[i] = ')' & s[i - 1] = ')'
             & if(s[i - d[i - 1] - 1] = '(')
             => dp[i] = dp[i - 1] + 2 + dp[i - dp[i - 1] - 2]
             demo
             idx 0 1 2 3 4 5
             s   ( ) ( ( ) )
             dp  0 2 0 0 3
             dp[5] 包含 三部分：
             dp[3],
             2(idx(2) idx(5)),
             dp[1] 1 = 5 - dp[3] - 2
             */
            int[] dp = new int[n];
            int ans = 0;
            for (int i = 1; i < n; i++) {
                if (cs[i] == '(') continue;
                if (cs[i - 1] == '(') {
                    dp[i] = dp[i - 2] + 2;
                } else {
                    if (i - dp[i - 1] > 0 && cs[i - dp[i - 1] - 1] == '(') {
                        dp[i] = dp[i - 1] + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0) + 2;
                    }
                }
                ans = Math.max(ans, dp[i]);
            }
            return ans;
        }

        public List<String> generateParenthesis(int n) {
            List<String> res = new ArrayList<>();
            if (n <= 0) return res;
//             dfs(n, "", res);
            dfs_ii(res, n, n, new StringBuilder(), n);
            return res;
        }

        private void dfs_ii(List<String> ans, int leftNum, int rightNum, StringBuilder sb, int len) {
            if (sb.toString().length() == len * 2) {
                ans.add(sb.toString());
                return;
            }

            if (leftNum > 0) {
                sb.append("(");
                dfs_ii(ans, leftNum - 1, rightNum, sb, len);
                sb.delete(sb.length() - 1, sb.length());
            }

            if (rightNum > leftNum) {
                sb.append(")");
                dfs_ii(ans, leftNum, rightNum - 1, sb, len);
                sb.delete(sb.length() - 1, sb.length());
            }
        }

        private void dfs(int n, String path, List<String> res) {
            if (path.length() == 2 * n) {
                res.add(path);
                return;
            }

            dfs(n, path + "(", res);
            dfs(n, path + ")", res);
        }


        public int maxProduct(int[] nums) {
            if (nums == null || nums.length == 0) {
                return 0;
            }

            /**
             dp[i][2]表示以i结尾的连续子数组的乘积 最小值 | 最大值
             n[i] = 0 : dp[i][0] = dp[i][1] = 0;
             n[i] > 0
             dp[i][0] = Math.min(dp[i - 1][0] * n[i], n[i]
             dp[i][1] = Math.max(dp[i - 1][1] * n[i], n[i]
             n[i] < 0
             dp[i][0] = Math.min(dp[i - 1][1] * n[i], n[i]
             dp[i][1] = Math.max(dp[i - 1][0] * n[i], n[i]
             -- 初始划
             dp[0][0] = n[0] = dp[0][1];
             */
            int n = nums.length;
            int[][] dp = new int[n][2];
            dp[0][0] = nums[0];
            dp[0][1] = nums[0];
            for (int i = 1; i < n; i++) {
                if (nums[i] == 0) {
                    dp[i][0] = 0;
                    dp[i][1] = 0;
                    continue;
                }
                if (nums[i] > 0) {
                    dp[i][0] = Math.min(dp[i - 1][0] * nums[i], nums[i]);
                    dp[i][1] = Math.max(dp[i - 1][1] * nums[i], nums[i]);
                } else {
                    dp[i][0] = Math.min(dp[i - 1][1] * nums[i], nums[i]);
                    dp[i][1] = Math.max(dp[i - 1][0] * nums[i], nums[i]);
                }
            }
            int res = Integer.MIN_VALUE;
            for (int i = 0; i < n; i++) {
                res = Math.max(res, dp[i][1]);
            }
            return res;
        }

        public int mySqrt(int x) {
            if (x < 0) {
                return 0;
            }
            if (x <= 1) {
                return x;
            }

            int l = 0, r = x >> 1;
            System.out.println("--: " + l + " - " + r);
            while (l + 1 < r) {

                int m = l + ((r - l) >> 1);
                System.out.println(l + " - " + r + " | " + m);
                long multi = 1L * m * m;
                if (multi == x) {
                    return m;
                } else if (multi < x) {
                    l = m;
                } else {
                    r = m;
                }
            }

            if (r * r <= x) return r;
            return l;
        }

        public int firstMissingPositive_ii(int[] nums) {
            if (nums == null || nums.length == 0) {
                return -1;
            }
            /**
             1: 将负数变为n+1
             2: 将小于n的下标值全部取反，表示该idx下有值
             3: 遍历 ，第一个值大于0的下边就是ans
             -- demo --
             3  4 -1 1
             3  4 5  1
             -3 4 5  -1
             */
            int n = nums.length;
            for (int i = 0; i < n; i++) {
                if (nums[i] <= 0) {
                    nums[i] = n + 1;
                }
            }
            for (int i = 0; i < n; i++) {
                int idx = Math.abs(nums[i]);
                if (idx <= n) {
                    nums[idx - 1] = -1 * Math.abs(nums[idx - 1]);
                }
            }
//            for(int i = 0; i < n; i ++){
//                System.out.println(nums[i]);
//            }
            for (int i = 0; i < n; i++) {
                if (nums[i] > 0) {
                    return i + 1;
                }
            }
            return n + 1;
        }

        public int firstMissingPositive(int[] nums) {
            if (nums == null || nums.length == 0) {
                return -1;
            }
            int n = nums.length;

            for (int i = 0; i < n; i++) {
                if (nums[i] > n || nums[i] <= 0 || nums[i] - 1 == i) {
                    continue;
                }
                int j = nums[i] - 1;
                while (i != j && j < n && j >= 0 && nums[i] != nums[j]) {
                    swap(nums, i, j);
                    j = nums[i] - 1;
                }
            }
            for (int i = 0; i < n; i++) {
                System.out.println(i + " - " + nums[i]);
            }
            for (int i = 0; i < n; i++) {
                System.out.println(i + " - " + (nums[i] - 1) + " - "
                        + (i != nums[i] - 1));
                if (i != nums[i] - 1) {
                    return i + 1;
                }
            }
            return n + 1;
        }

        private void swap(int[] nums, int i, int j) {
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
    }
}
